#include "apptimer.h"

unsigned int regnum = 1;      //计数器的编号
LIST_HEAD(timer_list); 			 	 //创建定时器链表

/*
 * 更新这个定时器的下一个到期时间如果他是个可重复的定时器
 */
void update_timer(struct app_timer *a)
{

	/* if this timer is just a newly created one then its
	 * t_last.tv_sec and t_last.tv_usec are 0
	 * 如果这个定时器仅仅是一个新创建的一个，
	 * then它的t_last.tv_sec核t_last.tv_usec 是0
	 */
    if(a->t_last.tv_sec == 0 && a->t_last.tv_usec == 0) {
        struct timeval t_now;

        /*
         * Never been called yet, call time `t' from now.  
		 * 从不被调用，
         */
        gettimeofday(&t_now, NULL);

		/* since it has never been called yet, we just presumebly let
		 * the timer's last expiry time as the current time
		 * 既然他从来不被调用，我们假定让当前时间作为timer的最后终止时间
		 */
        a->t_last.tv_sec = t_now.tv_sec;
        a->t_last.tv_usec = t_now.tv_usec;


		/* update this timer's next expiry time, and t.tv_sec is just the
		 * time's countdown number 
		 * 更新这个定时器的下一个到期时间，t.tv_sec是这个定时器的定时器数字
		 */
        a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec;
        a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec;

		/* if this time's tv_usec is greater than 1000 ms.
		 * 如果这个时间的tv_usec是大于1000ms */
        while(a->t_next.tv_usec >= 1000000) {
			/* decrease its tv_usec by 1000 ms.
			 * 减去1000ms */
            a->t_next.tv_usec -= 1000000;

			/* increase its tv_sec by 1000 ms.
			 * 增加1s */
            a->t_next.tv_sec += 1;
        }
    }
	 /* 如果这个定时器不是一个新的，而且他还没有设置下一个到期时间，这是
	 * 下面的情况
	 */
    else if(a->t_next.tv_sec == 0 && a->t_next.tv_usec == 0) {
        /*
         * We've been called but not reset for the next call.  
		 * 我们被调用但是重新设置for下一次调用
         */
        if(a->flags & SA_REPEAT) {
			 /* 如果这个定时器可重复，但是他的t是0，一些事情是错的，注意现在这个定时器
			 * 的t_next是0
			 */
            if(a->t.tv_sec == 0 && a->t.tv_usec == 0) {
                app_timer_unregister(a->clientreg);//注销这个定时器
                return;
            }

			 /* 注意既然这个可重复的定时器没有被重置下一个嗲用，我们仅仅重置它现在，然后稀少的
			 * 因为它是可重复的，它的下一个到期时间一定是上一个到期时间+倒计时数
			 */
            a->t_next.tv_sec = a->t_last.tv_sec + a->t.tv_sec;
            a->t_next.tv_usec = a->t_last.tv_usec + a->t.tv_usec;

            while(a->t_next.tv_usec >= 1000000) {
                a->t_next.tv_usec -= 1000000;
                a->t_next.tv_sec += 1;
            }
        }
        else {
            /*
             * Single time call, remove it.  
			 * 单个调用，用完就注销
             */
            app_timer_unregister(a->clientreg);
        }
    }

	
}

/**
* 这个函数注销这个回调函数从一个定时器注册链表，注销这个定时器
*    clientreg是一个独特的无字符整型量，代表了一个注册过的定时器which要注销的
*/
void app_timer_unregister(unsigned int clientreg)
{

    struct app_timer *sa_ptr;
	struct list_head *pos;

	/* sa_ptr通过遍历链表找到要注销的app_time结构体 */
	list_for_each(pos, &timer_list){
		sa_ptr = list_entry(pos,struct app_timer,list);
		if(sa_ptr->clientreg == clientreg)
			break;
	}


    if(sa_ptr != NULL) {
        printf("注销定时器 %d 号\n", sa_ptr->clientreg);
		list_del(&sa_ptr->list);
		(sa_ptr)->t.tv_sec = 0;
		(sa_ptr)->t.tv_usec = 0;
		(sa_ptr)->t_last.tv_sec = 0;
		(sa_ptr)->t_last.tv_usec = 0;
		(sa_ptr)->t_next.tv_sec = 0;
		(sa_ptr)->t_next.tv_usec = 0;
		(sa_ptr)->flags = 0;
		(sa_ptr)->clientarg = NULL;
		(sa_ptr)->thecallback = NULL;
		(sa_ptr)->clientreg = 0;
    }
    else {
    }
}


/*
 * 如果全局变量@timer_list被设置，我们重复来获得定时器whose下一个到期
 * 时间是最近的，如果@timer_list没有，就返回NULL
 */
struct app_timer *find_next_timer(void)
{
    struct app_timer *a, *lowest = NULL;
	struct list_head *pos;

	/* iterate in the timer list headed by timer_list, and find a timer 
	 * which has the most recent expiry time setting
	 */
	list_for_each(pos, &timer_list){
		a = list_entry(pos, struct app_timer, list);
		if(lowest == NULL)
			lowest = a;
		else if(a->t_next.tv_sec == lowest->t_next.tv_sec) {
			if(a->t_next.tv_usec < lowest->t_next.tv_usec) {
				lowest = a;
			}
		}else if(a->t_next.tv_sec < lowest->t_next.tv_sec) {
			lowest = a;
		}
	}

	return lowest;
}



/* 按clientreg找到相应的定时器结构体 */
struct app_timer *sa_find_specific(unsigned int clientreg)
{
	
    struct app_timer *sa_ptr;
	struct list_head *pos;

	list_for_each(pos,&timer_list){
		sa_ptr = list_entry(pos, struct app_timer, list);
        if(sa_ptr->clientreg == clientreg) {
            return sa_ptr;
        }
    }
    return NULL;
}

/*
 * call the callback function of a timer, which has expired
 * 调用一个到期的定时器的回调函数
 */
void run_timers(void)
{
    int done = 0;
    struct app_timer *a = NULL;
    unsigned int clientreg;
    struct timeval t_now;

    /*
     * Loop through everything we have repeatedly looking for the next thing to
     * call until all events are finally in the future again.  
	 *
     */

    while(!done) {
		/* find a timer which will have the most recent expiry time */
        if((a = find_next_timer()) == NULL) {
            return;
        }

        gettimeofday(&t_now, NULL);

		/* if the found timer do expire already */
        if((a->t_next.tv_sec < t_now.tv_sec) ||
           ((a->t_next.tv_sec == t_now.tv_sec) &&
            (a->t_next.tv_usec < t_now.tv_usec))) {

			/* since this timer's expiry time is small than the current time,
			 * which means its callback handler should be called at once
			 */
            clientreg = a->clientreg;


			/* note that here we call a->thecallback */
            (*(a->thecallback)) (clientreg, a->clientarg);


            if((a = sa_find_specific(clientreg)) != NULL) {
                a->t_last.tv_sec = t_now.tv_sec;
                a->t_last.tv_usec = t_now.tv_usec;
                a->t_next.tv_sec = 0;
                a->t_next.tv_usec = 0;
                
				/* update the timer's next expiry time */
                update_timer(a);
            }
            else {
            }
        }
        else {/* this timer has not expired yet */
            done = 1;
        }
    }

}

/*
 * 注意 timer_handler函数 是基础，这是其他定时器到期处理函数的来源，
 * 因此在timer_handler中我们首先调用这个到期的定时器的处理函数，然后
 * 选择另一个定时器在timer_list然后设置它的剩余时间，当然这个定时器
 * 将成为下一个到期的。
 */
void timer_handler(int a)
{
	/* call the expired timer's callback function 
	 * 调用到期的定时器的回调函数*/
    run_timers();

	/* choose the next timer and kick off it, and of course if run_timers
	 * run a lot of time, then the next one maybe expires behind its expiry
	 * time set before
	 * 选择下一个定时器然后踢开他，当然如果run_times运行了一段时间，下一个
	 * 定时器可能到期了在它的到期时间被设置之后
	 */
    set_an_timer();
}

/*
 * get the left expiry time for a timer and if none returns 0 
 * 获得最近到期定时器剩余时间写入delta
 */
int get_next_timer_delay_time(struct timeval *delta)
{
    struct app_timer *sa_ptr;
    struct timeval t_diff, t_now;

	/* find a timer in the timer list whose next expiry time is the smallest 
	 * 找到一个定时器在timer_list中whose 下一个终止时间是最小的*/
    sa_ptr = find_next_timer();

    if(sa_ptr) {
        gettimeofday(&t_now, 0);

		/* both of the two following cases represent that the current timer's next 
		 * expiry time(tv_sec) is less than the current time, namely it has not
		 * expired yet
		 * 下面这2个情况都代表了当前定时器的下一次到期时间(tv_sec)是小于当前时间，
		 * 就是说它还没有到期
		 */
        if((t_now.tv_sec > sa_ptr->t_next.tv_sec) ||
           ((t_now.tv_sec == sa_ptr->t_next.tv_sec) &&
            (t_now.tv_usec > sa_ptr->t_next.tv_usec))) {
            /*
             * Time has already passed.  Return the smallest possible amount of
             * time.  
			 * 时间已经过了，返回这个最小的可能的时间量
			 *
			 * 注意@t_next 是一个数字 for 代表了绝对时间这个定时器将要到期，and@t_now是一个变量，
			 * 这样如果@t_now超过了@t_next，它意味着这个定时器应该已经到期，这里我们仅仅让@delta
			 * 拥有最小的积极量来代表它已经到期，fortv_sec 和 tv_usec 不能都设置为0，不是他们能设置到消极
			 * 的量，就是这个timer停止了！我们将别无选择开启它调用get_next_timer_delay_time
             */
            delta->tv_sec = 0;
			/* we assume that in next 1 us this timer expires, why doing so? 
			 * 我们假象？？？ */
            delta->tv_usec = 1;


            return sa_ptr->clientreg;
        }
        else {
            /*
             * Time is still in the future. 
			 * 时间仍然在未来 
             */
            t_diff.tv_sec = sa_ptr->t_next.tv_sec - t_now.tv_sec;
            t_diff.tv_usec = sa_ptr->t_next.tv_usec - t_now.tv_usec;

            while(t_diff.tv_usec < 0) {
                t_diff.tv_sec -= 1;
                t_diff.tv_usec += 1000000;
            }

			/* @t_now doesn't exceed @t_next, this sa_ptr's next expiry time is 
			 * still valid, so we return this left time
			 * @t_now 没有超过@t_next,这个sa_ptr的下一个到期时间仍然有效，因此我们
			 * 返回这个剩余值
			 */
            delta->tv_sec = t_diff.tv_sec;
            delta->tv_usec = t_diff.tv_usec;



            return sa_ptr->clientreg;
        }
    }

    /*
     * Nothing Left.  
     */
    return 0;
}

/*
 * 踢开一个定时器如果下一个到期时间没有过
 */
void set_an_timer(void)
{

    struct timeval delta;
    int next_timer = get_next_timer_delay_time(&delta);//获取下一个最近的到期的定时器编号

    /*
	 * 我们不用信号如果他们要求我们，它预示着他们将要检查下一个定时器的时间然后调用
	 * 他们自己的run_timers。
     */

    if(next_timer) {//找到了相应的timer编号、已经将时间存入delta
        struct itimerval it;

        it.it_value.tv_sec = delta.tv_sec;//it_value设定第一次执行function所延迟的秒数
        it.it_value.tv_usec = delta.tv_usec;
        it.it_interval.tv_sec = 0;
        it.it_interval.tv_usec = 0;

		/* set the timer handler 
		 * 设置定时器处理函数*/
        signal(SIGALRM, timer_handler);

		/* kick off the timer */
        setitimer(ITIMER_REAL, &it, NULL);/* 以系统真实的时间来计算，它送出SIGALRM信号
											 当Linux setitimer()所执行的timer时间到了，
											 会呼叫SIGALRM signal，
											 第二个参数是sturct，负责设定timeout时间,
											 第三个参数会存放旧的timeout值，如果不需
											 要的话，指定NULL即可。
											 */


        /*printf("激活开启了 %d 号定时器在 %d.%03d 秒\n",*/
               /*next_timer, (int) delta.tv_sec,*/
               /*(int) (delta.tv_usec / 1000));*/

    }
    else {
        /*printf("no timers found to schedule\n");*/
    }
}


/**
* 这个函数注册回调函数到将来
*
*        when是一个无符号整数，指定当回调函数将在几秒后被调用
*
*    flags是一个无符号整数，指定如何经常在回调函数在几秒钟内被调用。应为
*    SA_PEPEAT或0.如果flag设置SA_REPEAT，然后注册回调函数将被每秒，如果为0，
*    这个函数只会被调用一次，然后从注册计时器链表中删除。
*
*    thecallback是一个指针APPTimerCallback就是回调函数被储存和登记。
*
*    clientarg是一个void指针，是当做参数被回调函数使用。这个指针指向app_timer->clientarg
*
*    返回值：是一个无符号整数(这也是作为每个回调的第一个参数)，然后可以用来
*    去除在使用中的一个app_timer_unregister()函数的？？。如果内存无法分配，
*    就返回0
*/
unsigned int
app_timer_register(struct app_timer *sa_ptr,unsigned int when, unsigned int flags,
                    APPTimerCallback * thecallback, void *clientarg)
{
	struct list_head *pos;

	/* 
	 * iterate from the timer list head(@timer_list), and the newly created 
	 * timer will just be queued at the tail of the list.
	 * 重复从timer_list头部，最新被创建的定时器将被入队到链表的尾部
	 */

	list_add_tail(&sa_ptr->list, &timer_list);


    if(sa_ptr == NULL)
        return 0;

	/* set the countdown number for this new timer being created 
	 * 设置这个倒计时数 for这个被创建的新的定时器*/
    if(0 == when) {
        (sa_ptr)->t.tv_sec = 0;
        (sa_ptr)->t.tv_usec = 1;
    }
    else {
        (sa_ptr)->t.tv_sec = when;
        (sa_ptr)->t.tv_usec = 0;
    }

	/* set other properties for this new timer 
	 * 设置其他的属性*/
	(sa_ptr)->t_last.tv_sec = 0;
	(sa_ptr)->t_last.tv_usec = 0;
	(sa_ptr)->t_next.tv_sec = 0;
	(sa_ptr)->t_next.tv_usec = 0;

    (sa_ptr)->flags = flags;
    (sa_ptr)->clientarg = clientarg;
    (sa_ptr)->thecallback = thecallback;
    (sa_ptr)->clientreg = regnum++;

    update_timer(sa_ptr);

    /*printf("创建完成定时器 %d 号, t = %d.%03d, flags=0x%02x\n",*/
           /*(sa_ptr)->clientreg, (int) (sa_ptr)->t.tv_sec,*/
           /*(int) ((sa_ptr)->t.tv_usec / 1000), (sa_ptr)->flags);*/

    //if(start_timer){
        set_an_timer();
    //}

    return (sa_ptr)->clientreg;
}
/*

int main()
{
	start_timer = 1;
	struct app_timer timer;

    app_timer_register(&timer, 5, 0,fun1,&timer);


    return 0;
}

*/
